package com.yc.cloud.openai.portal.dao.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.yc.cloud.common.basic.exception.Asserts;
import com.yc.cloud.common.basic.utils.PathUtils;
import com.yc.cloud.openai.portal.dao.SpeechToTextClient;
import com.yc.cloud.openai.portal.dao.TextToSpeechClient;
import com.yc.cloud.openai.portal.dto.request.SpeechToTextRequest;
import com.yc.cloud.openai.portal.dto.request.TextToSpeechRequest;
import com.yc.cloud.openai.portal.dto.response.SpeechToTextResponse;
import com.yc.cloud.openai.portal.dto.response.TextToSpeechResponse;
import com.yc.cloud.openai.portal.dto.response.XFSpeechToTextResponse;
import com.yc.cloud.openai.portal.enums.SpeechSpeaker;
import com.yc.cloud.openai.portal.utils.AudioUtils;
import com.yc.cloud.openai.portal.utils.MyFileUtils;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.stereotype.Service;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;

@Service("XUN_FEI")
@Slf4j
public class XunFeiClientImpl implements SpeechToTextClient, TextToSpeechClient {

    private static final String URL = "http://openapi.xfyun.cn/v2/aiui";

    //191****3095 这个账号下的内容
//    private static final String APPID = "8bb87ebd";
//    private static final String API_KEY = "a040ea63c183da81a81ea405294a2153";

    private static final String APPID = "9bf49835";
    private static final String API_KEY = "a03b4416b7c152aca248dda2a94cf565";

    private static final String IAT_DATA_TYPE = "audio";
    private static final String TTS_DATA_TYPE = "text";
    //iat专门使用该场景
    private static final String IAT_SCENE = "main-iat_box";
    private static final String TTS_SCENE = "IFLYTEK.tts";
    private static final String SAMPLE_RATE = "16000";
    private static final String AUTH_ID = "2894c985bf8b1111c6728db79d3479ae";
    private static final String AUE = "raw";
    private static final String SUCCESS_CODE = "0";
    private final String SUB_IAT = "iat";
    private final String SUB_TTS = "tts";

    private final PathUtils pathUtils;

    public XunFeiClientImpl(PathUtils pathUtils) {
        this.pathUtils = pathUtils;
    }

    @Override
    public SpeechToTextResponse convertSpeechToText(SpeechToTextRequest param) {
        val ttsStart = System.currentTimeMillis();
        val header = buildSpeechToTextHeader(param);
        String result = httpPost(header, param.getAudioData());
        if (StrUtil.isEmpty(result)) {
            return null;
        }
        log.info("科大讯飞语音转文本结果:{}", result);
        val xfSpeechToTextResponse = JSONUtil.toBean(result, XFSpeechToTextResponse.class);
        //响应失败
        if (!SUCCESS_CODE.equals(xfSpeechToTextResponse.getCode())) {
            log.error("科大讯飞语音转文本失败--->{}", xfSpeechToTextResponse.getDesc());
            Asserts.fail(xfSpeechToTextResponse.getDesc());
        }
        val resultDTO = new SpeechToTextResponse();
        val dataDTOList = xfSpeechToTextResponse.getData();
        val iatStringBuilder = new StringBuilder();
        dataDTOList.forEach(dataDTO -> {
            val sub = dataDTO.getSub();
            //后面测试发现iat结果会有多个,所以采用StringBuilder拼接
            if (SUB_IAT.equals(sub)) {
                iatStringBuilder.append(dataDTO.getText());
            }
        });
        resultDTO.setText(iatStringBuilder.toString());
        val ttsEnd = System.currentTimeMillis();
        val costTime = ttsEnd - ttsStart;
        resultDTO.setCostTime(costTime);
        log.info("科大讯飞语音转文本结果:{}", resultDTO.getText());
        return resultDTO;
    }

    @Override
    public TextToSpeechResponse convertTextToSpeech(TextToSpeechRequest request) {
        val ttsStart = System.currentTimeMillis();
        val header = buildTextToSpeechHeader(request);
        String result = httpPost(header, request.getText().getBytes(StandardCharsets.UTF_8));
        if (StrUtil.isEmpty(result)) {
            return null;
        }
      //  log.info("讯飞文本转语音结果:{}", result);
        val xfnlpApiResp = JSONUtil.toBean(result, XFSpeechToTextResponse.class);
        //响应失败
        if (!SUCCESS_CODE.equals(xfnlpApiResp.getCode())) {
            log.error("XFNLPApiServiceImpl ERROR--->{}", xfnlpApiResp.getDesc());
            Asserts.fail(xfnlpApiResp.getDesc());
        }
        val ttsResultDTO = new TextToSpeechResponse();
        ttsResultDTO.setText(request.getText());
        val dataDTOList = xfnlpApiResp.getData();
        dataDTOList.forEach(dataDTO -> {
            val sub = dataDTO.getSub();
            if (SUB_TTS.equals(sub)) {
                val wavBase64Data = getBase64AudioData(dataDTO.getContent());
                ttsResultDTO.setAudioData(wavBase64Data);
            }
        });
        val ttsEnd = System.currentTimeMillis();
        val costTime = ttsEnd - ttsStart;
        //重点关注下接口耗时,如果超过2秒,则需要优化接口
        if (costTime > 2000) {
            log.info("讯飞文本转语音花费时间:{},文本内容:{}", costTime, ttsResultDTO.getText());
        }
        return ttsResultDTO;
    }


    private String httpPost(Map<String, String> header, byte[] body) {
        StringBuilder result = new StringBuilder();
        BufferedReader in = null;
        OutputStream out = null;
        try {
            java.net.URL realUrl = new URL(URL);
            HttpURLConnection connection = (HttpURLConnection) realUrl.openConnection();
            for (String key : header.keySet()) {
                connection.setRequestProperty(key, header.get(key));
            }
            connection.setDoOutput(true);
            connection.setDoInput(true);

            //connection.setConnectTimeout(20000);
            //connection.setReadTimeout(20000);
            try {
                out = connection.getOutputStream();
                out.write(body);
                out.flush();
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }

            try {
                in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
                String line;
                while ((line = in.readLine()) != null) {
                    result.append(line);
                }
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return result.toString();
    }


    private Map<String, String> buildSpeechToTextHeader(SpeechToTextRequest request) {
        // 使用 HashMap 构建参数
        Map<String, String> params = new HashMap<>();
        params.put("aue", AUE);
        params.put("sample_rate", SAMPLE_RATE);
        params.put("auth_id", AUTH_ID);
        params.put("data_type", IAT_DATA_TYPE);
        params.put("scene", IAT_SCENE);
        return digest(params);
    }

    private Map<String, String> buildTextToSpeechHeader(TextToSpeechRequest request) {
        // 使用 HashMap 构建参数
        Map<String, String> params = new HashMap<>();
        params.put("aue", AUE);
        params.put("sample_rate", SAMPLE_RATE);
        params.put("auth_id", AUTH_ID);
        params.put("data_type", TTS_DATA_TYPE);
        params.put("scene", TTS_SCENE);
        params.put("tts_aue", AUE);
        //设置播报的发音人
        if (SpeechSpeaker.MAN.getValue().equals(request.getSpeaker().getValue())) {
            params.put("vcn", "x_qige");
        } else {
            params.put("vcn", "x2_xiaojuan");
        }
        return digest(params);
    }

    private Map<String, String> digest(Map<String, String> params) {
        String param = JSONUtil.toJsonStr(params);
        String curTime = System.currentTimeMillis() / 1000L + "";
        String paramBase64 = new String(Base64.encodeBase64(param.getBytes(StandardCharsets.UTF_8)));
        String checkSum = DigestUtils.md5Hex(API_KEY + curTime + paramBase64);
        Map<String, String> header = new HashMap<>();
        header.put("X-Param", paramBase64);
        header.put("X-CurTime", curTime);
        header.put("X-CheckSum", checkSum);
        header.put("X-Appid", APPID);
        return header;
    }

    /**
     * 获取base64音频数据
     *
     * @param content 音频编码数据
     * @return base64音频数据
     */
    private String getBase64AudioData(String content) {
        val pcmPath = Paths.get(pathUtils.getTempBasePath(), System.currentTimeMillis() + "-xf-tts.pcm").toString();
        MyFileUtils.decodeAndSaveFile(content, pcmPath);
        val wavPath = pcmPath.replace(".pcm", ".wav");
        //当前数据为pcm格式,使用ffmpeg将pcm数据转成wav,h5方便显示
        AudioUtils.pcm2wav(pcmPath, wavPath);
        return MyFileUtils.convertToBase64(FileUtil.file(wavPath));
    }


}
